package com.study.spmongodb.wwj.juc.utils;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;

/**
 * @author MI
 * @version 1.0
 * @date 2020/12/13 19:26
 */
public class ConditionExample3 {
    private static final ReentrantLock lock = new ReentrantLock();
    private final static Condition PRODUCE_COND = lock.newCondition();
    private final static Condition CONSUMER_COND = lock.newCondition();
    private final static LinkedList<Long> TIMESTAMP_POOL = new LinkedList<>();
    private final static int MAX_CAPACITY = 100;


    public static void main(String[] args) {
        IntStream.range(0, 6).boxed().forEach(ConditionExample3::beginProduce);
        IntStream.range(0, 13).boxed().forEach(ConditionExample3::beginConsumer);
        for (; ; ) {
            try {
                TimeUnit.SECONDS.sleep(5);
                System.out.println("======================");
         /*       final int waitQueueLength = lock.getWaitQueueLength(PRODUCE_COND);
                System.out.println("PRODUCE_COND" + waitQueueLength);
                System.out.println("CONSUMER" + lock.getWaitQueueLength(CONSUMER_COND));
          */
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    private static void beginConsumer(int i) {
        new Thread(() -> {
            for (; ; ) {
                consume();
                sleep(2);
            }

        }, "c" + i).start();
    }

    private static void beginProduce(int i) {
        new Thread(() -> {
            for (; ; ) {
                produce();
                sleep(2);
            }

        }, "p" + i).start();
    }


    private static void sleep(long sec) {
        try {
            TimeUnit.SECONDS.sleep(sec);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void produce() {

        lock.lock();
        try {
            while (TIMESTAMP_POOL.size() >= MAX_CAPACITY) {
                PRODUCE_COND.await();
            }

            final long millis = System.currentTimeMillis();
            System.out.println(Thread.currentThread().getName() + "-p-" + millis);
            TIMESTAMP_POOL.addLast(millis);
            CONSUMER_COND.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private static void consume() {
        lock.lock();
        try {
            while (TIMESTAMP_POOL.isEmpty()) {
                CONSUMER_COND.await();
            }
            final Long aLong = TIMESTAMP_POOL.removeFirst();
            System.out.println(Thread.currentThread().getName() + "-c-" + aLong);
            PRODUCE_COND.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
